package cn.zlp.user.service.impl;

import cn.zlp.basic.exception.BusinessException;
import cn.zlp.basic.service.impl.BaseServiceImpl;
import cn.zlp.basic.util.MD5Utils;
import cn.zlp.basic.util.StrUtils;
import cn.zlp.user.constant.UserConstant;
import cn.zlp.user.domain.Logininfo;
import cn.zlp.user.domain.User;
import cn.zlp.user.dto.UserDto;
import cn.zlp.user.mapper.LogininfoMapper;
import cn.zlp.user.mapper.UserMapper;
import cn.zlp.user.service.IUserService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * 店铺Service类,先继承公共的Service类,再实现接口
 */
@Service
public class UserServiceImpl extends BaseServiceImpl<User> implements IUserService {

    @Autowired
    @Qualifier("redisTemplate")
    private RedisTemplate redisTemplate;

    @Autowired(required = false)
    private UserMapper userMapper;

    @Autowired(required = false)
    private LogininfoMapper logininfoMapper;

    /**
     * 手机注册发送手机验证码
     * @param phone
     */
    @Override
    public void smsCode(String phone) {
        // 判断电话是否为空
        if (!StringUtils.hasLength(phone)) {
            throw new BusinessException("请输入正确的手机号!!!");
        }
        // 根据电话号码查询用户,看该号码是否被注册
        User user = userMapper.findByPhone(phone);
        if (user != null){ // 不为Null说明已经注册
            throw new BusinessException("该号码已经注册,请直接登录!!!");
        }
        // 获取redis数据库中的该号码手机注册的验证码
        Object obj = redisTemplate.opsForValue().get(UserConstant.REGISTER_CODE_PREFIX + phone);
        // 声明code来装验证码
        String code = null;
        if (obj != null){ // 验证码不为null,说明不是第一次登录
            code = obj.toString().split(":")[0];
            String timeString = obj.toString().split(":")[1];
            if (System.currentTimeMillis() - Long.parseLong(timeString) < 1*60*1000){ // 在重发时间内,时间没有超过60s
                throw new BusinessException("请不要重复获取验证码,稍后重试!!!");
            }
        } else { // 第一次注册或者验证码过期
            // 生成4为数字随机验证码
            code = StrUtils.getRandomString(4);
        }
        // 在redis数据库中保存该号码手机注册的最新验证码
        redisTemplate.opsForValue().set(UserConstant.REGISTER_CODE_PREFIX + phone,
                code+":"+System.currentTimeMillis(),3, TimeUnit.MINUTES);
        // SmsUtil.sendMsg(phone,"你的验证码是：" + code + ",请在3分钟之内使用");
        System.out.println("你的验证码是：" + code + ",请在3分钟之内使用");

    }

    /**
     * 手机注册
     * @param userDto
     */
    @Override
    @Transactional
    public void toRegister(UserDto userDto) {
        // 获取注册信息
        String phone = userDto.getPhone();
        String code = userDto.getCode();
        String password = userDto.getPassword();
        String rePassword = userDto.getRePassword();
        // 判断注册信息是否为空,一个为空都不执行
        if (StringUtils.isEmpty(phone)
                || StringUtils.isEmpty(code)
                || StringUtils.isEmpty(password)
                || StringUtils.isEmpty(rePassword)
            ) {
            throw new BusinessException("请输入正确的信息,信息不能为空!!!");
        }
        if (!password.equals(rePassword)) { // 判断两次密码是否一样
            throw new BusinessException("请重复正确的密码!!!");
        }
        // 获取redis数据库中的该号码手机注册的验证码
        Object obj = redisTemplate.opsForValue().get(UserConstant.REGISTER_CODE_PREFIX + phone);
        if (obj == null){
            throw new BusinessException("验证码无效,请重新获取最新验证码!!!");
        }
        // 获取验证码
        String code1 = obj.toString().split(":")[0];
        if (!code.equalsIgnoreCase(code1)){ // 忽略大小写进行比较
            throw new BusinessException("验证码错误,请输入正确的验证码!!!");
        }
        // 调用方法将userDto对象转换为user对象,这是一种思想,应用于对象转换
        User user = userDto2User(userDto);
        // 调用方法将user对象转换为logininfo对象
        Logininfo logininfo = user2Logininfo(user);
        // 添加登录信息
        logininfoMapper.save(logininfo);
        // 将登录信息的自增长主键赋值给登录信息id
        user.setLogininfo_id(logininfo.getId());
        // 添加用户
        userMapper.save(user);
    }

    /**
     * 微信绑定发送手机验证码
     * @param phone
     */
    @Override
    public void smsBinderCode(String phone) {
        // 判断电话是否为空
        if (!StringUtils.hasLength(phone)) {
            throw new BusinessException("请输入正确的手机号!!!");
        }
//        // 根据电话号码查询用户,看该号码是否被注册
//        User user = userMapper.findByPhone(phone);
//        if (user != null){ // 不为Null说明已经注册
//            throw new BusinessException("该号码已经注册,请直接登录!!!");
//        }
        // 获取redis数据库中的该号码手机注册的验证码
        Object obj = redisTemplate.opsForValue().get(UserConstant.BINDER_CODE_PREFIX + phone);
        // 声明code来装验证码
        String code = null;
        if (obj != null){ // 验证码不为null,说明不是第一次登录
            code = obj.toString().split(":")[0];
            String timeString = obj.toString().split(":")[1];
            if (System.currentTimeMillis() - Long.parseLong(timeString) < 1*60*1000){ // 在重发时间内,时间没有超过60s
                throw new BusinessException("请不要重复获取验证码,稍后重试!!!");
            }
        } else { // 第一次注册或者验证码过期
            // 生成4为数字随机验证码
            code = StrUtils.getRandomString(4);
        }
        // 在redis数据库中保存该号码手机注册的最新验证码
        redisTemplate.opsForValue().set(UserConstant.BINDER_CODE_PREFIX + phone,
                code+":"+System.currentTimeMillis(),3, TimeUnit.MINUTES);
        // SmsUtil.sendMsg(phone,"你的验证码是：" + code + ",请在3分钟之内使用");
        System.out.println("你的验证码是：" + code + ",请在3分钟之内使用");
    }

    @Override
    public void enable(List<Long> ids) {
        userMapper.enable(ids);
    }

    @Override
    public void disable(List<Long> ids) {
        userMapper.disable(ids);
    }

    /**
     * 手机登录时发送手机验证码
     * @param phone
     */
    @Override
    public void sendLoginCode(String phone) {
        // 判断电话是否为空
        if (!StringUtils.hasLength(phone)) {
            throw new BusinessException("请输入正确的手机号!!!");
        }
//        // 根据电话号码查询用户,看该号码是否被注册
//        User user = userMapper.findByPhone(phone);
//        if (user != null){ // 不为Null说明已经注册
//            throw new BusinessException("该号码已经注册,请直接登录!!!");
//        }
        // 获取redis数据库中的该号码手机注册的验证码
        Object obj = redisTemplate.opsForValue().get(UserConstant.LOGIN_CODE_PREFIX + phone);
        // 声明code来装验证码
        String code = null;
        if (obj != null){ // 验证码不为null,说明不是第一次登录
            code = obj.toString().split(":")[0];
            String timeString = obj.toString().split(":")[1];
            if (System.currentTimeMillis() - Long.parseLong(timeString) < 1*60*1000){ // 在重发时间内,时间没有超过60s
                throw new BusinessException("请不要重复获取验证码,稍后重试!!!");
            }
        } else { // 第一次注册或者验证码过期
            // 生成4为数字随机验证码
            code = StrUtils.getRandomString(4);
        }
        // 在redis数据库中保存该号码手机注册的最新验证码
        redisTemplate.opsForValue().set(UserConstant.LOGIN_CODE_PREFIX + phone,
                code+":"+System.currentTimeMillis(),3, TimeUnit.MINUTES);
        // SmsUtil.sendMsg(phone,"你的验证码是：" + code + ",请在3分钟之内使用");
        System.out.println("你的验证码是：" + code + ",请在3分钟之内使用");
    }

    private User userDto2User(UserDto userDto) {
        // 创建云用户,用于接收
        User user = new User();
        // 将userDto中的参数赋值到user中
        user.setUsername(userDto.getPhone());
        user.setPhone(userDto.getPhone());
        // 获取32位盐值
        String salt = StrUtils.getComplexRandomString(32);
        // 密码加密加盐
        String md5pwd = MD5Utils.encrypByMd5(userDto.getPassword() + salt);
        // 保存盐值
        user.setSalt(salt);
        // 保存加密后的密码
        user.setPassword(md5pwd);
        return user;
    }
    private Logininfo user2Logininfo(User user) {
        // 创建logininfo对象用于接收
        Logininfo logininfo = new Logininfo();
        // 将两个对象的相同属性进行拷贝
        BeanUtils.copyProperties(user,logininfo); // copyProperties复制相同属性(数据源对象,数据目标对象)
        // 设置用户类型1L,代表平台用户
        logininfo.setType(1);
        return logininfo;
    }

    @Override
    public void update(User user) {
        // 更具id查询用户,这样才可以获取登录信息id
        User user1 = userMapper.loadById(user.getId());
        // 获取修改后的加密加盐密码
        String mdspwd = MD5Utils.encrypByMd5(user.getPassword()+user.getSalt());
        // 设置新的密码
        user.setPassword(mdspwd);
        // 将修改的user对象转为修改的logininfo对象
        Logininfo logininfo = user2Logininfo(user);
        // 设置登录信息之前的id,也因为被覆盖了
        logininfo.setId(user1.getLogininfo_id());
        // 修改登录信息
        logininfoMapper.update(logininfo);
        // 修改user
        userMapper.update(user);
    }
}
